package team.bluepen.supermarket.service.recommend.core;

import team.bluepen.supermarket.service.recommend.dto.RelateDTO;

import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * 核心算法
 *
 * @author YCB 2023/6/19 15:01
 */
public class UserCF {

    /**
     * 方法描述: 推荐商品id列表
     *
     * @param userId 当前用户
     * @param list   用户商品评分数据
     * @return {@link List<Long>}
     */
    public static List<Long> recommend(Long userId, List<RelateDTO> list) {
        // 按用户分组：每一个元素都是同一用户的全部评价
        Map<Long, List<RelateDTO>> userMap = list.stream()
                .collect(Collectors.groupingBy(RelateDTO::getUserId));

        // 获取其他用户与当前用户的关系值：计算用户之间的相似度
        Map<Long, Double> userDisMap = CoreMath.computeNeighbor(userId, userMap, 0); // UserCF,计算相关系数并排序

        // 获取关系最近的用户(找最相似的用户)
        double maxValue = Collections.max(userDisMap.values());
        Set<Long> userIds = userDisMap.entrySet().stream()
                .filter(e -> e.getValue() == maxValue)
                .map(Map.Entry::getKey)
                .collect(Collectors.toSet());

        // 取关系最近的用户
        Long nearestUserId = userIds.stream()
                .findAny().orElse(null);
        if (nearestUserId == null) {
            return Collections.emptyList();
        }
        // 最相似用户看过商品列表
        List<Long> neighborItems = userMap.getOrDefault(nearestUserId, Collections.emptyList())
                .stream()
                .map(RelateDTO::getItemId)
                .collect(Collectors.toList());
        // 指定用户看过商品列表
        List<Long> userItems = userMap.getOrDefault(userId, Collections.emptyList())
                .stream()
                .map(RelateDTO::getItemId)
                .collect(Collectors.toList());
        // 找到最近邻看过，但是该用户没看过的商品
        neighborItems.removeAll(userItems);
        return neighborItems;
    }
}
